package service

import (
	"errors"
	"github.com/gin-gonic/gin"
	"github.com/zoumo/goset"
	"gorm.io/gorm"
	"guns-go/global"
	"guns-go/model"
	"guns-go/model/request"
	"guns-go/model/response"
	"guns-go/utils"
)

func GetLoginRoles(userId int) (err error, dictS []map[string]interface{}) {

	dictSlice := make([]map[string]interface{}, 0)

	err, RoleIds := GetUserRoleIdList(userId)

	if err != nil {
		return err, nil
	}

	if len(RoleIds) > 0 {
		errSysRole, sysRoles := GetSysRoleBatchIds(RoleIds)

		if errSysRole != nil {
			return errSysRole, nil
		}

		if len(sysRoles) > 0 {

			for _, sysRole := range sysRoles {
				dict := make(map[string]interface{}, 0)
				dict[global.ID] = sysRole.Id
				dict[global.CODE] = sysRole.Code
				dict[global.NAME] = sysRole.Name

				dictSlice = append(dictSlice, dict)
			}
		}
	}

	return err, dictSlice
}

func GetSysRoleBatchIds(ids []int) (err error, sysRoleS []model.SysRole) {

	var roles []model.SysRole
	err = global.GVA_DB.Where("id in (?)", ids).Where("status = 0").Find(&roles).Error

	return err, roles
}

func QuerySysRoleById(roleId int) (err error, r *model.SysRole) {

	var role *model.SysRole
	err = global.GVA_DB.Where("id = ?", roleId).First(&role).Error

	return err, role
}

func UpdateSysRole(role *model.SysRole, tx *gorm.DB) error {
	return tx.Model(&role).Updates(role).Error
}

func UpdateSysRoleById(id int, status int8, tx *gorm.DB) error {
	return tx.Model(model.SysRole{}).Where("id = ?", id).Update("status", status).Error
}

func QuerySysRoleBatchIds(ids []int) (err error, sysRoleS []model.SysRole) {

	var roles []model.SysRole
	err = global.GVA_DB.Where("id in (?)", ids).Find(&roles).Error

	return err, roles
}

func SaveRole(role *model.SysRole, tx *gorm.DB) error {
	return tx.Create(role).Error
}

func GetUserDataScopeIdList(roleIds []int, orgId int) (err error, ids []int) {

	resultSlice := make([]int, 0)

	//定义角色中最大数据范围的类型，目前系统按最大范围策略来，如果你同时拥有ALL和SELF的权限，系统最后按ALL返回
	strongerDataScopeType := int8(global.SELF)

	if len(roleIds) > 0 {

		err, sysRoles := QuerySysRoleBatchIds(roleIds)

		if err != nil {
			return err, nil
		}

		customDataScopeRoleIdSlice := make([]int, 0)

		if len(sysRoles) > 0 {
			for _, sysRole := range sysRoles {
				if sysRole.DataScopeType == global.DEFINE {
					customDataScopeRoleIdSlice = append(customDataScopeRoleIdSlice, sysRole.Id)
				} else {
					if sysRole.DataScopeType < strongerDataScopeType {
						strongerDataScopeType = sysRole.DataScopeType
					}
				}
			}
		}

		//自定义数据范围的角色对应的数据范围
		err, roleDataScopeIdSlice := GetRoleDataScopeIdList(customDataScopeRoleIdSlice)

		if err != nil {
			return err, nil
		}

		//角色中拥有最大数据范围类型的数据范围
		err, dataScopeIdSlice := GetDataScopeListByDataScopeType(strongerDataScopeType, orgId)

		if err != nil {
			return err, nil
		}

		resultSlice = append(resultSlice, roleDataScopeIdSlice...)
		resultSlice = append(resultSlice, dataScopeIdSlice...)

		pSet := goset.NewSafeSetFromInts(resultSlice)
		resultSlice = resultSlice[:0]
		resultSlice = append(resultSlice, pSet.ToInts()...)
	}

	return err, resultSlice
}

func RolePage(sysRoleParam *request.SysRoleParam, c *gin.Context) (err error, result *response.PageResult) {

	var sysRoles []*model.SysRole

	db := global.GVA_DB

	if sysRoleParam != nil {
		//根据名称模糊查询
		if sysRoleParam.Name != "" {
			db = db.Where("name like ? ", "%"+sysRoleParam.Name+"%")
		}

		//根据编码模糊查询
		if sysRoleParam.Code != "" {
			db = db.Where("code like ? ", "%"+sysRoleParam.Code+"%")
		}

		db = db.Where("status = ?", 0).Order("sort asc")

		var totalCount int64

		err = db.Find(&sysRoles).Count(&totalCount).Error

		if err != nil {
			return err, nil
		}

		pageNo, pageSize, db := utils.DefaultPage(c, db)

		err = db.Find(&sysRoles).Error

		if err != nil {
			return err, nil
		}
		return err, utils.CoverToPageResult(pageNo, pageSize, totalCount, sysRoles)
	}

	return err, nil
}

func RoleAdd(sysRoleParam *request.SysRoleParam) error {

	//校验参数，检查是否存在相同的名称和编码
	err := checkParamRole(sysRoleParam, false)

	if err != nil {
		return err
	}

	sysRole := new(model.SysRole)

	err = utils.SimpleCopyProperties(sysRole, sysRoleParam)

	if err != nil {
		return err
	}

	var zero int8
	zero = 0
	sysRole.Status = &zero

	tx := global.GVA_DB.Begin()

	err = SaveRole(sysRole, tx)

	if err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()
	return nil
}

func RoleEdit(sysRoleParam *request.SysRoleParam) error {

	err, sysRole := QuerySysRoleById(sysRoleParam.Id)

	if err != nil {
		return err
	}

	if sysRole.Id == 0 {
		return errors.New("角色不存在")
	}

	//校验参数，检查是否存在相同的名称和编码
	err = checkParamRole(sysRoleParam, true)
	if err != nil {
		return err
	}

	err = utils.SimpleCopyProperties(sysRole, sysRoleParam)

	if err != nil {
		return err
	}

	sysRole.Status = nil

	tx := global.GVA_DB.Begin()

	err = UpdateSysRole(sysRole, tx)

	if err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}

func RoleDelete(sysRoleParam *request.SysRoleParam) error {

	err, sysRole := QuerySysRoleById(sysRoleParam.Id)

	if err != nil {
		return err
	}

	if sysRole.Id == 0 {
		return errors.New("角色不存在")
	}

	tx := global.GVA_DB.Begin()

	err = UpdateSysRoleById(sysRole.Id, 2, tx)

	if err != nil {
		tx.Rollback()
		return err
	}

	id := sysRole.Id

	//级联删除该角色对应的角色-数据范围关联信息
	err = DeleteRoleDataScopeListByRoleId(id, tx)
	if err != nil {
		tx.Rollback()
		return err
	}

	//级联删除该角色对应的用户-角色表关联信息
	err = DeleteUserRoleListByRoleId(id, tx)
	if err != nil {
		tx.Rollback()
		return err
	}
	//级联删除该角色对应的角色-菜单表关联信息
	err = DeleteRoleMenuListByRoleId(id, tx)
	if err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}

func checkParamRole(sysRoleParam *request.SysRoleParam, isExcludeSelf bool) error {

	id := sysRoleParam.Id
	name := sysRoleParam.Name
	code := sysRoleParam.Code

	var sysRoleSlice []*model.SysRole

	db := global.GVA_DB
	// 查询名称有无重复
	dbName := db.Where("name = ?", name).Where("status <> ?", 2)
	// 查询编码有无重复
	dbCode := db.Where("code = ?", code).Where("status <> ?", 2)

	if isExcludeSelf {
		dbName = dbName.Where("id <> ?", id)
		dbCode = dbCode.Where("id <> ?", id)
	}

	var countByName int64
	err := dbName.Find(&sysRoleSlice).Count(&countByName).Error

	if err != nil {
		return err
	}

	var countByCode int64
	err = dbCode.Find(&sysRoleSlice).Count(&countByCode).Error

	if err != nil {
		return err
	}

	if countByName >= 1 {
		return errors.New("角色名称重复，请检查name参数")
	}

	if countByCode >= 1 {
		return errors.New("角色编码重复，请检查code参数")
	}
	return nil
}

func RoleGrantMenu(sysRoleParam *request.SysRoleParam) error {

	err, sysRole := QuerySysRoleById(sysRoleParam.Id)

	if err != nil {
		return err
	}

	if sysRole.Id == 0 {
		return errors.New("角色不存在")
	}

	tx := global.GVA_DB.Begin()

	err = RoleMenuGrantMenu(sysRoleParam, tx)

	if err != nil {
		tx.Rollback()
		return err
	}

	tx.Commit()
	return nil
}

func RoleGrantData(sysRoleParam *request.SysRoleParam, c *gin.Context) error {

	err, sysRole := QuerySysRoleById(sysRoleParam.Id)

	if err != nil {
		return err
	}

	if sysRole.Id == 0 {
		return errors.New("角色不存在")
	}

	err, superAdmin := IsSuperAdmin(c)

	if err != nil {
		return err
	}

	//如果登录用户不是超级管理员，则进行数据权限校验
	if !superAdmin {
		dataScopeType := sysRoleParam.DataScopeType
		//如果授权的角色的数据范围类型为全部，则没权限，只有超级管理员有
		if dataScopeType == 1 {
			return errors.New("没有权限操作该数据，请联系管理员")
		}
		//如果授权的角色数据范围类型为自定义，则要判断授权的数据范围是否在自己的数据范围内
		if dataScopeType == 5 {
			dataScope := sysRoleParam.DataScope
			//要授权的数据范围列表
			grantOrgIdSlice := sysRoleParam.GrantOrgIdList

			if len(grantOrgIdSlice) > 0 {
				isContain, _ := utils.Contain(grantOrgIdSlice, dataScope)

				//数据范围为空
				if len(dataScope) < 0 {
					return errors.New("没有权限操作该数据，请联系管理员")
				} else if !isContain {
					//所要授权的数据不在自己的数据范围内
					return errors.New("没有权限操作该数据，请联系管理员")
				}
			}
		}
	}

	sysRole.DataScopeType = sysRoleParam.DataScopeType

	tx := global.GVA_DB.Begin()

	err = UpdateSysRole(sysRole, tx)

	if err != nil {
		tx.Rollback()
		return err
	}

	err = RoleGrantDataScope(sysRoleParam, tx)

	if err != nil {
		tx.Rollback()
		return err
	}
	tx.Commit()
	return nil
}

func RoleOwnMenu(sysRoleParam *request.SysRoleParam) (error, []int) {

	err, sysRole := QuerySysRoleById(sysRoleParam.Id)

	if err != nil {
		return err, nil
	}

	if sysRole.Id == 0 {
		return errors.New("角色不存在"), nil
	}

	roleIds := make([]int, 0)
	roleIds = append(roleIds, sysRole.Id)

	err, menuIds := GetRoleMenuIdList(roleIds)

	if err != nil {
		return err, nil
	}

	return nil, menuIds
}

func RoleOwnData(sysRoleParam *request.SysRoleParam) (error, []int) {

	err, sysRole := QuerySysRoleById(sysRoleParam.Id)

	if err != nil {
		return err, nil
	}

	if sysRole.Id == 0 {
		return errors.New("角色不存在"), nil
	}

	roleIds := make([]int, 0)
	roleIds = append(roleIds, sysRole.Id)

	err, scopeIds := GetRoleDataScopeIdList(roleIds)

	if err != nil {
		return err, nil
	}

	return nil, scopeIds
}
